/**
 * 表格数据管理
 * 
 * 支持表格数据转到luckysheet中
 * 
 * G.fj add 2024.9.29
 * 
 * 功能:
 * 1.根据后台luckysheet模板创建luckyheet
 * 2.根据后台模板及提供的数据源,对数据进行填充luckysheet，并创建luckysheet
 * 3.创建luckysheet模板
 */


/**
 * 数据填充变量规则
 * U = 向上  D = 向下  L = 向左   R = 向右
 *    A                   B                    C                          ...
 * ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————
 * 1                      ${ds.title}                                     $代表数据源的单个数据，例：${ds.data[0][3]}
 * 2  ...                 ...                                             ...
 * 3  ${ds.colNames[0]}   ${ds.colNames[1]}    ${ds.colNames[2]}          单个填充:设置单个单元格
 * 4  $R{ds.colNames}                                                     自动填充:单元格根据colNames一维数据向右填充
 * 5  $D{ds.getCols(0)}   $D{ds.getCols(1)}                               自动填充:单元格根据cols一维数据向下填充
 * 6  $R{ds.getRows(0)}                                                   自动填充:单元格根据rows一维数据向下填充
 * 7  ${ds.datas}                                                         自动填充:单元格根据datas二维数据向右，向下填充
 * 8  ...
 * 
 * 注：
 *  a.填充时，增加的单元格保留设置单元格的格式
 *  b.新增时，参数单元格的被增加单元格的格式向填充方向移动，同时保留单元格的格式及数据
 */

/**
 * 数据源格式
 * datasource:{
 *      id:                                                             //数据库唯一标识
 *      tid:                                                            //模板唯一标识（索引）
 *      name:                                                           //数据源名称
 *      alais:                                                          //数据源中文名称
 *      dsType:"data/image"                                           //数据或图片
 *      dsUrl:{url:"",type:"POST | GET",params:{page:$page,size:20}}  //访问后台的地址 $打头的需要由模板检索参数替代
 * 
 *      function resCallback(res)                                       //如果数据格式不是标准的，则需要传入处理函数，返回数据集格式，res为http请求返回的结果,默认为标准格式
 *  }
 */
/**
 * 数据集   数据源加载后形成的数据
 * dataSet{
 *      id:                                                             //数据库唯一标识
 *      tid:                                                            //模板唯一标识
 *      name:
 *      alais:
 *      
 *      cols:[列名...],                                                 //数据源列名称，数据源标准格式，
 *      data:[[...]...],                                                //数据源数据，数据源标准格式
 * 
 *      page:                                                           //当前页码
 *      size:                                                           //每页数量
 *      total:                                                          //总数量
 * 
 *      function getCols(),                                             //读取一列的数据
 *      function getRows(),                                             //读取一行的数据
 *      function getDatas(),                                            //读取行列表格的数据
 *      function getData(row,col)                                       //读取表格中的数据指定位置的数据
 *      ...
 * }
 */
/**
 * 电子表格模板
 * SheetTemplate{ 
 *      id                                                              //数据库唯一标识
 *      name                                                            //模板名称
 *      alias                                                           //模板标题(中文名称)
 *      params:[{name:"英文名称",alias:"中文名称",value:"参数值"}... ]    //前端输入参数，用于加载数据源、图片源等      
 *      sources:[datasource...]                                         //数据源列表
 *      options:{column:10,row:10,config:{},...}                        //模板中关于sheet的相关参数
 */
/**
 * 电子表格渲染录入管理器
 * SpreadSheetManager{ * 
 *      //公用函数 
 *      function create(container,tpl,params)                           //根据数据源及参数创建sheet表
 *      function getSheet(order|name)                                   //得到sheet的参数，包括数据等，也可以是模板 返回:{}
 *      function getSheets()                                            //得到所有sheet的参数，包括数据等，也可以是模板 返回:{}
 *      function getLuckySheet()                                        //得到luckysheet实例，用于外部操作单元格等
 *      function importExcel(file)                                      //导入Excel文件
 *      function getSheetTemplate()                                     //得到设置的模板,用于后台保存
 *      function getDatasets()                                          //得到表格处理后的数据源(即根据模板的填充模式，将sheet的数据返回到数据源中，用于后台进行保存)
 * 
 *      //私有属性
 *      spreadSheet:{container:"luckysheet-cotainer",tpl:{},...}        //输入的参数,私有      
 * 
 *      //私有函数
 *      function fillSheetData()                                        //遍历模板内的sheets，根据输入数据源，图片源填充每个sheet的单元格
 *      function reverseDataset()                                       //加载数据源数据，用于填充模板数据
 * }
 */
class DsUrl {
    private url: string
    private type: string
    private params: Map<string, any>
    constructor(url, type, params) {
        this.url = url;
        this.type = type;
        this.params = params;
    }
}
class Datasource {
    private id: string
    private tid: string;
    private name: string;
    private alias: string;
    private dsType: string;
    private dsUrl: DsUrl;
    // 数据库唯一标识
    constructor(id, tid, name, alias, dsType, dsUrl) {
        this.id = id;
        this.tid = tid;
        this.name = name;
        this.alias = alias;
        this.dsType = dsType;
        this.dsUrl = dsUrl;
    }
    // 获取数据库唯一标识
    getId() {
        return this.id;
    }
    // 获取模板唯一标识（索引）
    getTid() {
        return this.tid;
    }
    // 获取数据源名称
    getName() {
        return this.name;
    }
    // 获取数据源中文名称
    getAlias() {
        return this.alias;
    }
    // 获取数据或图片类型
    getDsType() {
        return this.dsType;
    }
    // 获取访问后台的地址
    getDsUrl() {
        return this.dsUrl;
    }
    // 设置数据源名称
    setName(name) {
        this.name = name;
    }
    // 设置数据源中文名称
    setAlias(alias) {
        this.alias = alias;
    }
    // 设置数据或图片类型
    setDsType(dsType) {
        this.dsType = dsType;
    }
    // 设置访问后台的地址
    setDsUrl(dsUrl) {
        this.dsUrl = dsUrl;
    }
    // 显示数据源信息
    displayInfo() {
        console.log(`ID: ${this.id}`);
        console.log(`TID: ${this.tid}`);
        console.log(`Name: ${this.name}`);
        console.log(`Alias: ${this.alias}`);
        console.log(`DsType: ${this.dsType}`);
        console.log(`DsUrl:`, this.dsUrl);
    }
}
class Dataset {
    // 数据库唯一标识
    private id: string;
    // 模板唯一标识
    private tid: string;
    // 名称
    private name: string;
    // 别名
    private alias: string;
    // 数据源列名称，数据源标准格式
    private columns: Map<string, string>[];
    // 数据源数据，数据源标准格式
    private rows: any[][];
    // 当前页码
    private page: number;
    // 每页数量
    private size: number;
    // 总记录数
    private total: number;

    // 构造函数，用于初始化对象
    constructor(
        id: string,
        tid: string,
        name: string,
        alias: string,
        columns: Map<string, string>[],
        rows: any[][],
        page: number,
        size: number,
        total: number
    ) {
        this.id = id;
        this.tid = tid;
        this.name = name;
        this.alias = alias;
        this.columns = columns;
        this.rows = rows;
        this.page = page;
        this.size = size;
        this.total = total;
    }

    // 获取数据库唯一标识
    public getId(): string {
        return this.id;
    }

    // 获取模板唯一标识
    public getTid(): string {
        return this.tid;
    }

    // 获取名称
    public getName(): string {
        return this.name;
    }

    // 获取别名
    public getAlias(): string {
        return this.alias;
    }

    // 获取数据源列名称
    public getColumns(): Map<string, string>[] {
        return this.columns;
    }

    // 获取数据
    public getRows(): any[][] {
        return this.rows;
    }

    // 获取当前页码
    public getPage(): number {
        return this.page;
    }

    // 获取每页数量
    public getSize(): number {
        return this.size;
    }

    // 获取总记录数
    public getTotal(): number {
        return this.total;
    }

    // 设置当前页码
    public setPage(page: number): void {
        this.page = page;
    }

    // 设置每页数量
    public setSize(size: number): void {
        this.size = size;
    }

    // 设置总记录数
    public setTotal(total: number): void {
        this.total = total;
    }

    // 显示数据源信息
    public displayInfo(): void {
        console.log(`ID: ${this.id}`);
        console.log(`TID: ${this.tid}`);
        console.log(`Name: ${this.name}`);
        console.log(`Alias: ${this.alias}`);
        console.log(`Columns:`, this.columns);
        console.log(`Rows:`, this.rows);
        console.log(`Page: ${this.page}`);
        console.log(`Size: ${this.size}`);
        console.log(`Total: ${this.total}`);
    }

    //读取一列的数据 
    public getCols(col: string | number) {
        let colIndex: number;
        if (typeof col === 'string') {
            // 查找列名对应的索引
            colIndex = -1;
            for (let i = 0; i < this.columns.length; i++) {
                if (this.columns[i].has(col)) {
                    colIndex = i;
                    break;
                }
            }
            if (colIndex === -1) {
                throw new Error(`Column "${col}" not found.`);
            }
        } else {
            // 直接使用列索引
            colIndex = col;
        }

        // 提取指定列的数据
        return this.rows.map(row => row[colIndex]);
    }
}
class Param {
    // 参数名称
    private name: string;
    // 参数别名
    private alias: string;
    // 参数值
    private value: any;
    // 构造函数，用于初始化对象
    constructor(name: string, alias: string, value: any) {
        this.name = name;
        this.alias = alias;
        this.value = value;
    }
    // 获取参数名称
    public getName(): string {
        return this.name;
    }
    // 获取参数别名
    public getAlias(): string {
        return this.alias;
    }
    // 获取参数值
    public getValue(): any {
        return this.value;
    }
    // 设置参数名称
    public setName(name: string): void {
        this.name = name;
    }
    // 设置参数别名
    public setAlias(alias: string): void {
        this.alias = alias;
    }
    // 设置参数值
    public setValue(value: any): void {
        this.value = value;
    }
    // 显示参数信息
    public displayInfo(): void {
        console.log(`Name: ${this.name}`);
        console.log(`Alias: ${this.alias}`);
        console.log(`Value: ${this.value}`);
    }
}
class SheetTemplate {
    // 数据库唯一标识
    private id: string;
    // 模板名称
    private name: string;
    // 模板标题(中文名称)
    private alias: string;
    // 前端输入参数，用于加载数据源、图片源等
    private params: Param[];
    // 数据源列表
    private sources: Datasource[];
    // 模板中关于 sheet 的相关参数
    private options: Map<string, any>;
    // 构造函数，用于初始化对象
    constructor(
        id: string,
        name: string,
        alias: string,
        params: Param[],
        sources: Datasource[],
        options: Map<string, any>
    ) {
        this.id = id;
        this.name = name;
        this.alias = alias;
        this.params = params;
        this.sources = sources;
        this.options = options;
    }

    // 获取数据库唯一标识
    public getId(): string {
        return this.id;
    }
    // 获取模板名称
    public getName(): string {
        return this.name;
    }
    // 获取模板标题(中文名称)
    public getAlias(): string {
        return this.alias;
    }
    // 获取前端输入参数
    public getParams(): Param[] {
        return this.params;
    }
    // 获取数据源列表
    public getSources(): Datasource[] {
        return this.sources;
    }
    // 获取模板中关于 sheet 的相关参数
    public getOptions(): Map<string, any> {
        return this.options;
    }
    // 设置模板名称
    public setName(name: string): void {
        this.name = name;
    }
    // 设置模板标题(中文名称)
    public setAlias(alias: string): void {
        this.alias = alias;
    }
    // 设置前端输入参数
    public setParams(params: Param[]): void {
        this.params = params;
    }
    // 设置数据源列表
    public setSources(sources: Datasource[]): void {
        this.sources = sources;
    }
    // 设置模板中关于 sheet 的相关参数
    public setOptions(options: Map<string, any>): void {
        this.options = options;
    }
    // 显示模板信息
    public displayInfo(): void {
        console.log(`ID: ${this.id}`);
        console.log(`Name: ${this.name}`);
        console.log(`Alias: ${this.alias}`);
        console.log(`Params:`, this.params);
        console.log(`Sources:`, this.sources);
        console.log(`Options:`, this.options);
    }
}
export class SpreadSheetManager {
    // 容器标识
    private container: string;
    // 模板对象
    private tpl: SheetTemplate;
    // 参数列表
    private params: Param[];
    //后台请求的工具如axios
    private http: any
    // 构造函数，用于初始化对象
    constructor(container: string, tpl: SheetTemplate, params: Param[]) {
        this.container = container;
        this.tpl = tpl;
        this.params = params;
    }
    // 获取容器标识
    public getContainer(): string {
        return this.container;
    }
    // 获取模板对象
    public getTemplate(): SheetTemplate {
        return this.tpl;
    }
    // 获取参数列表
    public getParams(): Param[] {
        return this.params;
    }
    // 设置容器标识
    public setContainer(container: string): void {
        this.container = container;
    }
    // 设置模板对象
    public setTemplate(tpl: SheetTemplate): void {
        this.tpl = tpl;
    }
    // 设置参数列表
    public setParams(params: Param[]): void {
        this.params = params;
    }
    // 显示管理器信息
    public displayInfo(): void {
        console.log(`Container: ${this.container}`);
        console.log(`Template:`, this.tpl);
        console.log(`Params:`, this.params);
    }

    //公用函数 
    public create() {   //根据数据源及参数创建sheet表
        //加载数据源数据
        this.loadDataset()
        //填充表格用数据
        this.fillSheetData()

    }
    //  function getSheet(order|name)                                               //得到sheet的参数，包括数据等，也可以是模板 返回:{}
    //  function getSheets()                                            //得到所有sheet的参数，包括数据等，也可以是模板 返回:{}
    //  function getLuckySheet()                                        //得到luckysheet实例，用于外部操作单元格等
    //  function importExcel(file)                                      //导入Excel文件
    //  function getSheetTemplate()                                     //得到设置的模板,用于后台保存
    //  function getDatasets()                                          //得到表格处理后的数据源(即根据模板的填充模式，将sheet的数据返回到数据源中，用于后台进行保存)
    public reloadDataset(params: Param[]) {                             //重新加载表格数据，包括分页等相关参数

    }
    //  //私有属性
    //  spreadSheet:{container:"luckysheet-cotainer",tpl:{},...}        //输入的参数,私有      

    //  //私有函数
    private fillSheetData() {                                      //遍历模板内的sheets，根据输入数据源，图片源填充每个sheet的单元格
    }
    private loadDataset() {         //加载数据源数据，用于填充模板数据,并处理数据成dataset格式
    }
}